if(!jsx3.lang.Class.forName("tibco.admin.deployment.sa.su.nodeMap.NodeMap")) {

    /**
    **/
    jsx3.lang.Package.definePackage("tibco.admin.deployment.sa.su.nodeMap", function (nodeMapp) {
    });

    /**
    *
    **/
    jsx3.lang.Class.defineClass("tibco.admin.deployment.sa.su.nodeMap.NodeMap",
            jsx3.lang.Object,
            [tibco.admin.deployment.sa.su.SUDetailInterface],
            function(nodeMap) {
                // handler for this project and GUI interface.
                nodeMap.prototype.server = tibco.admin.Main.getServer();
                nodeMap.prototype.rootNode = null;

                // this property used for save modify state.
                nodeMap.prototype.hasModified = false;

                // this property used for save present mode.
                nodeMap.prototype.visionMode = "view";

                // these variables are used for call service backend.
                nodeMap.prototype.envEntifyID = null;
                nodeMap.prototype.serviceAssemblyID = null;
                nodeMap.prototype.serviceUnitID = null;

                nodeMap.prototype.onDestroy = function() {
                    this.unsubscribeAll();
                };

                nodeMap.prototype.subscribeAll = function() {
                    // subscribe service unit list selected message.
                    var me = this;
                    tibco.admin.PubSub.subscribe(tibco.admin.deployment.sa.su.sulist.EventID.SERVICEUNIT_ROW_SELECTED,
                            me, me.onServiceUnitSelected);
                };

                nodeMap.prototype.unsubscribeAll = function() {
                    var me = this;
                    tibco.admin.PubSub.unsubscribe(tibco.admin.deployment.sa.su.sulist.EventID.SERVICEUNIT_ROW_SELECTED,
                            me, me.onServiceUnitSelected);
                };

                nodeMap.prototype.onServiceUnitSelected = function(objEvent) {
                    var root = this.rootNode;

                    this.envEntifyID = objEvent.envEntityID;
                    this.serviceAssemblyID = objEvent.saEntityID;
                    this.serviceUnitID = objEvent.suEntityID;

                    // clear and reset lists interface with empty data.
                    root.getDescendantOfName("mtxMappedNodes_44B").clearXmlData();
                    root.getDescendantOfName("mtxMappedNodes_44B").repaintData();
                    // call web service to get node mapping data. When everything is OK.
                    if(this.serviceAssemblyID && this.serviceUnitID)
                    {
                        this.callgetServiceUnitNodeMappings();
                        root.getDescendantOfName("btnEdit_44B").setEnabled(jsx3.gui.Form.STATEENABLED, true);
                        root.getDescendantOfName("btnRefresh_44B").setEnabled(jsx3.gui.Form.STATEENABLED, true);
                    }
                    else
                    {
                        root.getDescendantOfName("btnEdit_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                        root.getDescendantOfName("btnRefresh_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                        return;
                    }

                    if(this.visionMode == "edit")
                    {
                        // reset modified status
                        this.hasModified = false;
                        // clear and reset lists interface with empty data.
                        root.getDescendantOfName("mtxAvailableNodes_44B").clearXmlData();
                        root.getDescendantOfName("mtxAvailableNodes_44B").repaintData();
                        root.getDescendantOfName("btnAddMappedNodes_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);

                        // call web service to get available nodes data. When everything is OK.
                        if(this.envEntifyID && this.serviceAssemblyID && this.serviceUnitID)
                        {
                            this.callgetAvailableNodesforServiceUnit();
                        }
                    }
                };

                /**
                 * method used for set UI vision mode
                 * mode {string} the value specified what type of vision you want to setting.
                 **/
                nodeMap.prototype.setVisionMode = function(mode) {
                    var root = this.rootNode;
                    this.visionMode = mode;
                    root.getDescendantOfName("lytVertical_44B").setDimensionArray(mode == "edit" ? ["30%",50,"*"] : [0, 0 , "*"], true);
                    root.getDescendantOfName("btnEdit_44B").setDisplay(mode == "edit" ? jsx3.gui.Block.DISPLAYNONE : jsx3.gui.Block.DISPLAYBLOCK, true);
                    root.getDescendantOfName("btnCancel_44B").setDisplay(mode == "edit" ? jsx3.gui.Block.DISPLAYBLOCK : jsx3.gui.Block.DISPLAYNONE, true);
                    root.getDescendantOfName("btnSave_44B").setDisplay(mode == "edit" ? jsx3.gui.Block.DISPLAYBLOCK : jsx3.gui.Block.DISPLAYNONE, true);
                    root.getDescendantOfName("mcStatus_44B").setDisplay(mode == "edit" ? jsx3.gui.Block.DISPLAYBLOCK : jsx3.gui.Block.DISPLAYNONE, true);
                    root.getDescendantOfName("mcServiceUnitStatus_44B").setDisplay(mode == "view" ? jsx3.gui.Block.DISPLAYBLOCK : jsx3.gui.Block.DISPLAYNONE, true);
                    root.getDescendantOfName("mcProblems_44B").setDisplay(mode == "view" ? jsx3.gui.Block.DISPLAYBLOCK : jsx3.gui.Block.DISPLAYNONE, true);
                    root.getDescendantOfName("chkStartAllNodes_44B").setEnabled(mode == "edit" ? jsx3.gui.Form.STATEENABLED : jsx3.gui.Form.STATEDISABLED, true);

                    if(mode == "view")
                    {
                        // reset modified status.
                        this.hasModified = false;
                        root.getDescendantOfName("mtxAvailableNodes_44B").clearXmlData();
                        root.getDescendantOfName("mtxAvailableNodes_44B").repaintData();
                        root.getDescendantOfName("btnAddMappedNodes_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                    }
                };

                nodeMap.prototype.isItemSelected = function(strMtxName) {
                    var root = this.rootNode;
                    var selectedNodes = root.getDescendantOfName(strMtxName).getSelectedNodes();
                    return selectedNodes.size() > 0;
                };

                nodeMap.prototype.onEdit = function() {
                    this.beginEditMode();
                    this.setVisionMode("edit");
                    this.callgetAvailableNodesforServiceUnit();
                };

                nodeMap.prototype.onCancel = function() {
                    this.endEditMode();
                    // if edit nothing, just return.
                    if(!this.hasModified)
                    {
                        this.setVisionMode("view");
                        return;
                    }

                    var me = this;
                    // popup up a confirm dialog, when user click the cancel button.
                    tibco.admin.Main.confirm(this.server.getDynamicProperty("@@confirmTitle_44B"),
                            this.server.getDynamicProperty("@@discardEdit_44B"),
                            function(confirmationDialog)
                            {
                                me.setVisionMode("view");
                                me.callgetServiceUnitNodeMappings();
                                confirmationDialog.doClose();
                            },
                            function(confirmationDialog)
                            {
                                confirmationDialog.doClose();
                            }, "Yes", "No", 2, null, null, "");
                };

                /**
                 * Called when user click Save button
                 */
                nodeMap.prototype.onSave = function() {
                    this.callupdateServiceUnitNodeMappings();
                };

                /**
                 * call this when "Mapped Nodes Matrix" has been selected.
                 */
                nodeMap.prototype.mtxMappedNodes_44B_OnSelect = function() {
                    var root = this.rootNode;
                    root.getDescendantOfName("btnRemoveMappedNodes_44B").setEnabled(
                            this.isItemSelected("mtxMappedNodes_44B") ? jsx3.gui.Form.STATEENABLED : jsx3.gui.Form.STATEDISABLED, true);
                };

                /**
                 * call this when "Available Nodes Matrix" has been selected.
                 */
                nodeMap.prototype.mtxAvailableNodes_44B_OnSelect = function() {
                    var root = this.rootNode;
                    root.getDescendantOfName("btnAddMappedNodes_44B").setEnabled(
                            this.isItemSelected("mtxAvailableNodes_44B") ? jsx3.gui.Form.STATEENABLED : jsx3.gui.Form.STATEDISABLED, true);
                };

                /**
                 * call this when "Add Mapped Button" has been clicked.
                 */
                nodeMap.prototype.btnAddMappedNodes_44B_OnClick = function() {
                    var root = this.rootNode;
                    var mtxAvailableNodes = root.getDescendantOfName("mtxAvailableNodes_44B");
                    var mtxMappedNodes = root.getDescendantOfName("mtxMappedNodes_44B");
                    var btnAddMappedNodes = root.getDescendantOfName("btnAddMappedNodes_44B");
                    var btnRemoveMappedNodes = root.getDescendantOfName("btnRemoveMappedNodes_44B");
                    var hasAdded = false;
                    var availableNodesSelectedIds = mtxAvailableNodes.getSelectedIds();

                    for(var i = 0; i < availableNodesSelectedIds.length; i++)
                    {
                        var availableNodesRecord = mtxAvailableNodes.getRecordNode(availableNodesSelectedIds[i]);
                        if(!availableNodesRecord.getAttribute("hasMapped"))
                        {
                            mtxMappedNodes.insertRecordNode(availableNodesRecord.cloneNode(), "jsxroot");
                            mtxAvailableNodes.deleteRecord(availableNodesSelectedIds[i], false);
                            mtxMappedNodes.selectRecord(availableNodesSelectedIds[i]);
                            hasAdded = true;
                            this.hasModified = true;
                        }
                    }

                    btnAddMappedNodes.setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                    mtxAvailableNodes.deselectAllRecords();

                    if(hasAdded)
                    {
                        btnRemoveMappedNodes.setEnabled(jsx3.gui.Form.STATEENABLED, true);
                        mtxAvailableNodes.repaintData();
                        mtxMappedNodes.repaintData();
                    }
                };

                /**
                 * call this when "Remove Mapped Button" has been clicked.
                 */
                nodeMap.prototype.btnRemoveMappedNodes_44B_OnClick = function() {
                    var root = this.rootNode;
                    var mtxAvailableNodes = root.getDescendantOfName("mtxAvailableNodes_44B");
                    var mtxMappedNodes = root.getDescendantOfName("mtxMappedNodes_44B");
                    var btnAddMappedNodes = root.getDescendantOfName("btnAddMappedNodes_44B");
                    var btnRemoveMappedNodes = root.getDescendantOfName("btnRemoveMappedNodes_44B");
                    var hasRemoved = false;
                    var mappedNodesSelectedIds = mtxMappedNodes.getSelectedIds();

                    for(var i = 0; i < mappedNodesSelectedIds.length; i++)
                    {
                        var availableNodesRecord = mtxMappedNodes.getRecordNode(mappedNodesSelectedIds[i]);
                        mtxAvailableNodes.insertRecordNode(availableNodesRecord.cloneNode(), "jsxroot");
                        mtxMappedNodes.deleteRecord(mappedNodesSelectedIds[i], false);
                        mtxAvailableNodes.selectRecord(mappedNodesSelectedIds[i]);
                        hasRemoved = true;
                        this.hasModified = true;
                    }

                    btnRemoveMappedNodes.setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                    mtxMappedNodes.deselectAllRecords();

                    if(hasRemoved)
                    {
                        btnAddMappedNodes.setEnabled(jsx3.gui.Form.STATEENABLED, true);
                        mtxAvailableNodes.repaintData();
                        mtxMappedNodes.repaintData();
                    }
                };

                /** 070805
                 * set the status of "btnAddMappedNodes_44B" and "btnRemoveMappedNodes_44B" buttons.
                 * called by the on the Drop Event of "mtxAvailableNodes_44B" and "mtxMappedNodes_44B" in UI.
                 */
                nodeMap.prototype.setArrowBtns = function() {
                    this.rootNode.getDescendantOfName("btnAddMappedNodes_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                    this.rootNode.getDescendantOfName("btnRemoveMappedNodes_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                    this.rootNode.getDescendantOfName("mtxMappedNodes_44B").deselectAllRecords();
                    this.rootNode.getDescendantOfName("mtxAvailableNodes_44B").deselectAllRecords();
                    this.hasModified = true;
                }

                /** 070805
                 * refresh the "mtxMappedNodes_44B" list,
                 * and if it's in edit mode, refresh the "mtxAvailableNodes_44B" list as well.
                 */
                nodeMap.prototype.refresh = function() {
                    this.callgetServiceUnitNodeMappings();
                    if(this.visionMode == "edit") this.callgetAvailableNodesforServiceUnit();
                }

                /**
                 * call web service to get all mapped nodes.
                 */
                nodeMap.prototype.callgetServiceUnitNodeMappings = function() {
                    if(this.isInEditMode()) {
                        return;
                    }
                    var objService = tibco.admin.Main.loadService("tibco.admin",
                            "tibco/admin/deployment/sa/su/nodeMap/rules/getServiceUnitNodeMappings.xml",
                            "getServiceUnitNodeMappings");
                    objService.setEndpointURL(tibco.admin.util.ServiceHelper.getDeploymentEndpointURL());
                    objService.serviceAssemblyID = this.serviceAssemblyID;
                    objService.serviceUnitID = this.serviceUnitID;

                    var me = this;
                    objService.subscribe(jsx3.net.Service.ON_SUCCESS, me, me.ongetServiceUnitNodeMappingsSuccess);
                    objService.doCall();
                };

                nodeMap.prototype.ongetServiceUnitNodeMappingsSuccess = function(objEvent) {
                    var root = this.rootNode;
                    root.getDescendantOfName("btnRemoveMappedNodes_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                    root.getDescendantOfName("mtxMappedNodes_44B").repaintData();
                };

                nodeMap.prototype.ongetServiceUnitNodeMappingsError = function(objEvent) {
                };

                nodeMap.prototype.ongetServiceUnitNodeMappingsInvalid = function(objEvent) {
                };

                /**
                 * call web service to get all available nodes.
                 */
                nodeMap.prototype.callgetAvailableNodesforServiceUnit = function() {
                    var objService = tibco.admin.Main.loadService("tibco.admin",
                            "tibco/admin/deployment/sa/su/nodeMap/rules/getAvailableNodes.xml",
                            "getAvailableNodesforServiceUnit");
                    objService.setEndpointURL(tibco.admin.util.ServiceHelper.getDeploymentEndpointURL());
                    objService.envEntifyID = this.envEntifyID;
                    objService.serviceAssemblyID = this.serviceAssemblyID;
                    objService.serviceUnitID = this.serviceUnitID;

                    var me = this;
                    objService.subscribe(jsx3.net.Service.ON_SUCCESS, me, me.ongetAvailableNodesforServiceUnitSuccess);
                    objService.doCall();
                };

                nodeMap.prototype.ongetAvailableNodesforServiceUnitSuccess = function(objEvent) {
                    var server = this.server;
                    var root = this.rootNode;
                    var cdfMappedNodes = server.getCache().getDocument("XMLCacheMappedNodes_44B");
                    var cdfAvailableNodes = server.getCache().getDocument("XMLCacheAvailableNodes_44B");
                    if(!cdfMappedNodes || !cdfAvailableNodes) {
                        return;
                    }

                    var mappedNodesList = cdfMappedNodes.getChildNodes();
                    var mappedNodesLength = cdfMappedNodes.getChildNodes().size();
                    var availableNodesList = cdfAvailableNodes.getChildNodes();
                    var availableNodesLength = cdfAvailableNodes.getChildNodes().size();

                    // give available node in "XMLCacheAvailableNodes_44B" a new "hasMapped" attriubte.
                    for(var i = 0; i < mappedNodesLength; i++)
                    {
                        for(var j = 0; j < availableNodesLength; j++)
                        {
                            if(mappedNodesList.getItem(i).getAttribute("jsxid") ==
                               availableNodesList.getItem(j).getAttribute("jsxid"))
                            {
                                cdfAvailableNodes.deleteRecord(availableNodesList.getItem(j).getAttribute("jsxid"), false);
                                break;
                            }
                        }
                    }

                    root.getDescendantOfName("mtxAvailableNodes_44B").repaintData();
                };

                nodeMap.prototype.ongetAvailableNodesforServiceUnitError = function(objEvent) {
                };

                nodeMap.prototype.ongetAvailableNodesforServiceUnitInvalid = function(objEvent) {
                };

                /**
                 * call web service to update service unit node mapping.
                 */
                nodeMap.prototype.callupdateServiceUnitNodeMappings = function() {
                    var objService = tibco.admin.Main.loadService("tibco.admin",
                            "tibco/admin/deployment/sa/su/nodeMap/rules/updateServiceUnitNodeMappings.xml",
                            "updateServiceUnitNodeMappings");
                    objService.setEndpointURL(tibco.admin.util.ServiceHelper.getDeploymentEndpointURL());
                    objService.serviceAssemblyID = this.serviceAssemblyID;
                    objService.serviceUnitID = this.serviceUnitID;

                    var me = this;
                    objService.subscribe(jsx3.net.Service.ON_SUCCESS, me, me.onupdateServiceUnitNodeMappingsSuccess);
                    objService.doCall();
                };

                nodeMap.prototype.onupdateServiceUnitNodeMappingsSuccess = function(objEvent) {
                    this.endEditMode();
                    this.setVisionMode("view");

                    // refresh SA List -> su list -> mapped node list.
                    var message = new Object();
                    message.subject = tibco.admin.deployment.sa.updateSA.EventID.SERVICEASSEMBLY_UPDATED;
                    tibco.admin.PubSub.publish(message);
                };

                nodeMap.prototype.onupdateServiceUnitNodeMappingsError = function(objEvent) {
                };

                nodeMap.prototype.onupdateServiceUnitNodeMappingsInvalid = function(objEvent) {
                };

                nodeMap.getInstance = function(args) {
                    return new tibco.admin.deployment.sa.su.nodeMap.NodeMap();
                }

                nodeMap.prototype.onAfterComponentUnloaded = function() {
                }

                nodeMap.prototype.loadComponent = function(parent) {
                    var me = this;
                    tibco.admin.Main.loadUIResourceAsync(parent, "tibco.admin", "tibco/admin/deployment/sa/su/nodeMap/ui/nodeMap.xml", me, me.componentLoaded, true);
                }

                nodeMap.prototype.componentLoaded = function(objEvent) {
                    if(objEvent.status == "SUCCESS") {
                        this.rootNode = objEvent.obj;
                        this.rootNode.getDescendantOfName("btnAddMappedNodes_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                        this.rootNode.getDescendantOfName("btnRemoveMappedNodes_44B").setEnabled(jsx3.gui.Form.STATEDISABLED, true);
                        var me = this;
                        this.rootNode.handler = me;
                        this.setVisionMode(this.visionMode);
                        this.subscribeAll()
                    }
                    else {
                        if(objEvent.exception)
                        {
                            tibco.admin.Main.logException(objEvent.exception, objEvent.message);
                        }
                        else {
                            jsx3.log(objEvent.message);
                        }
                    }
                }

                nodeMap.prototype.getTabText = function() {
                    return tibco.admin.Main.getServer().getDynamicProperty("@tabNodeMapping_40");
                }

                /**
                 * Call this method when mouse move on any matix cell.
                 */
                nodeMap.prototype.mtxMappedNodes_44B_Spyglass = function(strRECORDID, objCOLUMN) {
                    if(objCOLUMN.getName() == "mcProblems_44B")
                    {
                        var root = this.rootNode;
                        var mtxMappedNodes = root.getDescendantOfName("mtxMappedNodes_44B");
                        var recordNode = mtxMappedNodes.getRecordNode(strRECORDID);
                        var problems = recordNode.getAttribute("summary");
                        if(problems)
                        {
                            return "<div style='width:300;'><b>" +
                                   this.server.getDynamicProperty("@@mcProblems_44B") +
                                   ":</b><div>" + problems.replace(/\n/g, "<br>") + "</div></div>";
                        }
                    }
                };

                nodeMap.prototype.tabSelected = function() {
                    if(!this.isInEditMode() && this.serviceAssemblyID && this.serviceUnitID)
                    {
                        this.callgetServiceUnitNodeMappings();
                    }
                }

            });
}